<route>
  {
    style: {
      navigationBarTitleText: 'AI模拟面试',
    }
  }
</route>

<script lang="ts" setup>
import { AudioToTextAPI, sendMessageToAI } from '@/api/interview'
import { ref, nextTick } from 'vue'
import { useTimer } from '@/hooks/useTimer'

// 计时器工具
const { formattedTime, start, pause, reset } = useTimer()
// 消息列表
const hintText = ref('')
// 回答内容
const answerContent = ref('')

// 语音状态（提问/倾听）
const voiceStatus = ref(false)

// websocket连接
const ttsSocketTask = ref<UniApp.SocketTask>()
const chatSocketTask = ref<UniApp.SocketTask>()

// 获取chatId
const query = defineProps<{
  chatId: string
  position: string
}>()

const sendParams = ref({
  prompt: '',
  chatId: query.chatId,
  position: query.position,
})

// 发送消息给面试官
const handleSend = async (prompt: string) => {
  if (!prompt) return
  answerContent.value = prompt
  sendParams.value.prompt = prompt
  await sendMessageToAI(sendParams.value)
  voiceStatus.value = true
  handleAIMsg()
  // console.log(sendParams.value)
  // 实现文本转语音
  textToSpeech()
}

// 音频播放队列
const audioQueue: string[] = []
let isPlaying = false
const audioCache: ArrayBuffer[] = []
let mergeTimer: number | null = null

// 建立新的TTS连接
const createNewTTSConnection = () => {
  const url = import.meta.env.VITE_APP_WS_BASEURL + '/member/ws/tts/' + query.chatId
  audioQueue.length = 0
  audioCache.length = 0
  const newTTSSocket = uni.connectSocket({
    url: url,
    complete: (res) => {
      console.log('ttsSocketTask连接已打开', res)
    },
  })
  newTTSSocket.onOpen(() => {
    newTTSSocket.onMessage(async (res) => {
      if (res.data === 'EOS') {
        console.log('TTS 流结束')
        voiceStatus.value = false
        // 记录问题数
        if (questionCount.value < 10) {
          questionCount.value++
        }
        newTTSSocket.close({
          complete: () => {
            console.log('ttsSocketTask连接已关闭')
          },
        })
        return
      }
      const arrayBuffer = res.data as ArrayBuffer
      // 加入音频缓存
      audioCache.push(arrayBuffer)

      if (!mergeTimer) {
        mergeTimer = setTimeout(() => {
          mergeAndPlayAudios()
        }, 500)
      }
    })
  })
}

// 文本转语音并实时播放（按顺序播放）
const textToSpeech = async () => {
  // 建立新的TTS连接
  createNewTTSConnection()
}

// 将多个 ArrayBuffer 对象合并成一个完整的 ArrayBuffer
function concatenateArrayBuffers(buffers: ArrayBuffer[]): ArrayBuffer {
  const totalLength = buffers.reduce((sum, buf) => sum + buf.byteLength, 0)
  const result = new Uint8Array(totalLength)
  let offset = 0
  for (const buffer of buffers) {
    result.set(new Uint8Array(buffer), offset)
    offset += buffer.byteLength
  }
  return result.buffer
}

// 合并多个音频，写入临时文件
async function mergeAndPlayAudios() {
  if (audioCache.length === 0) return

  // 清除定时器
  if (mergeTimer) {
    clearTimeout(mergeTimer)
    mergeTimer = null
  }

  // 合并音频
  const mergedBuffer = concatenateArrayBuffers(audioCache)
  audioCache.length = 0 // 清空缓存

  // 生成临时路径
  const tempFile = `${wx.env.USER_DATA_PATH}/merged_audio_${Date.now()}.mp3`

  // 写入文件
  wx.getFileSystemManager().writeFile({
    filePath: tempFile,
    data: mergedBuffer,
    encoding: 'binary',
    success: () => {
      enqueueAudio(tempFile)
    },
    fail: (err) => {
      console.error('合并音频写入失败', err)
    },
  })
}

// 将音频加入播放队列
function enqueueAudio(filePath: string) {
  audioQueue.push(filePath)
  if (!isPlaying) {
    playNextAudio()
  }
}

// 播放下一个音频
function playNextAudio() {
  console.log('playNextAudio')
  if (audioQueue.length === 0) {
    isPlaying = false
    return
  }

  isPlaying = true
  const currentFile = audioQueue.shift()!

  const innerAudioContext = wx.createInnerAudioContext()
  innerAudioContext.src = currentFile

  innerAudioContext.onPlay(() => {
    // console.log('开始播放:', currentFile)
    if (isRecording.value && canCancel.value) {
      console.log('playNextAudio1111111111')
      innerAudioContext.stop()
      return
    }
  })
  innerAudioContext.onEnded(() => {
    // console.log('播放结束:', currentFile)
    wx.getFileSystemManager().unlink({
      filePath: currentFile,
      success: () => {
        // console.log('已删除:', currentFile)
      },
    })
    playNextAudio() // 播放下一个
  })

  innerAudioContext.onError((res) => {
    console.error('播放错误:', res.errMsg, res.errCode)
    playNextAudio() // 跳过当前错误音频，继续播放下一个
  })

  innerAudioContext.play()
}

// 页面加载
onLoad(async () => {
  chatSocketTask.value = uni.connectSocket({
    url: import.meta.env.VITE_APP_WS_BASEURL + '/member/ws/interview/' + query.chatId,
    complete: (res) => {
      console.log('chatSocketTask连接已打开', res)
      console.log(query.chatId)
    },
  })
  await handleSend('你好,面试官')
})

onMounted(() => {
  start() // 页面加载后启动计时器
})

// 处理AI返回的消息
const handleAIMsg = async () => {
  let accumulatedContent = ''
  await chatSocketTask.value.onMessage(async (res) => {
    const data = res.data
    if (typeof data === 'string') {
      if (data === '[END]') {
        return
      }
      accumulatedContent += data
      await nextTick(() => {
        hintText.value = accumulatedContent
        // console.log(accumulatedContent)
      })
    }
  })
}

// 面试题数
const questionCount = ref(0)

// 面试信息
const interviewInfo = ref({
  position: query.position,
})

// 录音相关状态
const recorderManager = uni.getRecorderManager()
const isRecording = ref(false)
const touchStartY = ref(0)

// 录音相关方法
// 开始录音
const handleRecordStart = (e: any) => {
  touchStartY.value = e.touches[0].clientY
  isRecording.value = true

  // 开始录音
  recorderManager.start({
    duration: 60000, // 最长录音时间，单位ms
    sampleRate: 16000, // 采样率
    numberOfChannels: 1, // 录音通道数
    encodeBitRate: 96000, // 编码码率
    format: 'wav', // 音频格式
  })
}

// 录音取消
// 添加一个变量来追踪是否处于可取消状态
const canCancel = ref(false)

const handleRecordMove = (e: any) => {
  console.log('handleRecordMove')
  if (!isRecording.value) return

  const moveY = e.touches[0].clientY
  const distance = moveY - touchStartY.value

  // 上滑超过50px时只更新状态，不取消录音
  canCancel.value = distance < -50
  console.log('canCancel:', canCancel.value)
}

const handleRecordEnd = () => {
  // console.log(canCancel.value)
  // if (isRecording.value) {
  //   if (canCancel.value) {
  //     // 如果在可取消状态下松开，才取消录音
  //     isRecording.value = false
  //     recorderManager.stop()
  //     canCancel.value = false
  //     uni.showToast({
  //       title: '已取消录音',
  //       icon: 'none',
  //     })
  //     console.log('取消录音')
  //     // 重置取消状态
  //   } else {
  //     // 正常结束录音的逻辑
  //     console.log('正常结束录音')
  //     isRecording.value = false
  //     recorderManager.stop()
  //     recorderManager.onStop(async (res) => {
  //       const { tempFilePath } = res
  //       console.log('录音文件路径:', tempFilePath)
  //       const fs = wx.getFileSystemManager()
  //       const arrayBuffer = fs.readFileSync(tempFilePath)
  //       const { msg } = await AudioToTextAPI(arrayBuffer)
  //       answerContent.value = msg
  //       handleSend(answerContent.value)
  //       // // 重置取消状态
  //       canCancel.value = false
  //     })
  //   }
  // }
  recorderManager.stop()
  recorderManager.onStop(async (res) => {
    if (isRecording.value) {
      if (canCancel.value) {
        uni.showToast({
          title: '已取消录音',
          icon: 'none',
        })
      } else {
        const { tempFilePath } = res
        console.log('录音文件路径:', tempFilePath)
        const fs = wx.getFileSystemManager()
        const arrayBuffer = fs.readFileSync(tempFilePath)
        const { msg } = await AudioToTextAPI(arrayBuffer)
        answerContent.value = msg
        handleSend(answerContent.value)
      }
      // // 重置取消状态
      isRecording.value = false
      canCancel.value = false
    }
  })
}

// 页面卸载
onUnload(() => {
  // 页面卸载时关闭socket连接
  ttsSocketTask.value?.close({})
  ttsSocketTask.value = null
  chatSocketTask.value?.close({})
  chatSocketTask.value = null
  if (mergeTimer) {
    clearTimeout(mergeTimer)
    mergeTimer = null
  }
  audioCache.length = 0
})
</script>

<template>
  <view class="interview-chat">
    <!-- 面试官信息 -->
    <view class="interviewer-info">
      <image class="avatar" src="/static/images/interviewer-avatar.png" mode="aspectFill" />
      <view class="name">Sarah - 资深面试官</view>
    </view>
    <!-- 语音状态 -->
    <view class="voice-status" v-if="voiceStatus">
      <view
        style="
          width: 115.58px;
          height: 40px;
          display: flex;
          justify-content: center;
          align-items: center;
          background-color: #e8f0fe;
          color: #2563eb;
          padding: 0 20rpx;
          border-radius: 45rpx;
        "
      >
        面试官提问中...
      </view>
    </view>
    <view class="voice-status" v-else>
      <view class="voice-indicator">
        <view class="indicator-ring ring-outer"></view>
        <view class="indicator-ring ring-middle"></view>
        <view class="indicator-ring ring-inner"></view>
        <!-- <view class="indicator-dot"></view> -->
      </view>
      <text class="status-text">正在倾听...</text>
    </view>

    <!-- 面试信息卡片 -->
    <view class="interview-card">
      <view class="card-title">当前面试</view>
      <view class="info-row">
        <text class="label">面试岗位</text>
        <text class="value">{{ interviewInfo.position }}</text>
      </view>
      <view class="info-row">
        <text class="label">面试时长</text>
        <text class="value">已进行 {{ formattedTime }}</text>
      </view>
      <view class="info-row">
        <text class="label">面试进度</text>
        <text class="value">第{{ questionCount }}个问题/共10个</text>
      </view>
    </view>

    <!-- 问题提示 -->
    <view class="question-hint">
      <text class="hint-text">{{ answerContent }}</text>
    </view>

    <!-- 回答内容 -->
    <view class="answer-content">
      {{ hintText }}
    </view>

    <!-- 控制按钮组 -->
    <view class="control-buttons" v-if="voiceStatus">
      <view class="control-btn record">
        <i class="iconfont icon-cc-mic-close" style="font-size: 32px; color: #fff"></i>
      </view>
    </view>
    <view class="control-buttons" v-else>
      <view
        class="control-btn"
        :class="[canCancel ? 'close' : 'record']"
        @touchstart="handleRecordStart"
        @touchmove="handleRecordMove"
        @touchend="handleRecordEnd"
        @touchcancel="handleRecordEnd"
      >
        <i
          class="iconfont"
          :class="[canCancel ? 'icon-quxiao' : 'icon-mic']"
          style="font-size: 32px; color: #fff"
        ></i>
        <text class="record-tip" v-if="isRecording">
          {{ canCancel ? '松开取消' : '上滑取消' }}
        </text>
      </view>
    </view>

    <!-- 面试技巧提示 -->
    <view class="interview-tips">
      <view class="tips-title">面试技巧</view>
      <view class="tips-content">回答问题时请注意语速和语气，保持专业和自信</view>
    </view>
  </view>
</template>

<style lang="scss" scoped>
.interview-chat {
  min-height: 100vh;
  background-color: #ffffff;
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
}

.nav-bar {
  padding: 44px 16px 10px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  background-color: #ffffff;

  .nav-title {
    font-size: 17px;
    font-weight: 600;
    color: #333;
  }

  .nav-left,
  .nav-right {
    padding: 8px;
    font-size: 20px;
  }
}

.interviewer-info {
  margin-top: 20rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  .avatar {
    width: 120px;
    height: 120px;
    border-radius: 50%;
    background-color: #ffa07a;
    margin-bottom: 12px;
  }

  .name {
    font-size: 17px;
    font-weight: 500;
    color: #333;
  }
}

.voice-status {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 20px 0;

  .voice-indicator {
    position: relative;
    width: 80px;
    height: 80px;
    margin-bottom: 8px;

    .indicator-ring {
      position: absolute;
      border-radius: 50%;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      animation: pulse 2s ease-in-out infinite;
    }

    .ring-outer {
      width: 80px;
      height: 80px;
      background-color: rgba(64, 128, 255, 0.1);
      animation-delay: 0.4s;
    }

    .ring-middle {
      width: 60px;
      height: 60px;
      background-color: rgba(64, 128, 255, 0.2);
      animation-delay: 0.2s;
    }

    .ring-inner {
      width: 40px;
      height: 40px;
      background-color: rgba(64, 128, 255, 0.3);
    }

    .indicator-dot {
      position: absolute;
      width: 16px;
      height: 16px;
      background-color: #4080ff;
      border-radius: 50%;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
  }

  @keyframes pulse {
    0% {
      transform: translate(-50%, -50%) scale(0.95);
      opacity: 1;
    }
    50% {
      transform: translate(-50%, -50%) scale(1);
      opacity: 0.8;
    }
    100% {
      transform: translate(-50%, -50%) scale(0.95);
      opacity: 1;
    }
  }

  .status-text {
    font-size: 14px;
    color: #666;
  }
}

.countdown-status {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin: 20px 0;

  .countdown-indicator {
    position: relative;
    width: 80px;
    height: 80px;
    margin-bottom: 8px;
  }

  .countdown-circle {
    position: absolute;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background-color: #f8f9fa;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1;

    .countdown-number {
      font-size: 24px;
      font-weight: 600;
      color: #3b65fe;
    }
  }

  .countdown-progress {
    position: absolute;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background: conic-gradient(#3b65fe var(--progress), transparent var(--progress));
    animation: rotate 1s linear infinite;
    --progress: calc(((30 - var(--countdown)) / 30) * 100%);
  }

  .status-text {
    font-size: 14px;
    color: #666;
  }
}

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.interview-card {
  margin: 16px;
  padding: 16px;
  background-color: #f8f9fa;
  border-radius: 12px;

  .card-title {
    font-size: 16px;
    font-weight: 500;
    color: #333;
    margin-bottom: 12px;
  }

  .info-row {
    display: flex;
    justify-content: space-between;
    margin-bottom: 8px;

    .label {
      color: #666;
      font-size: 14px;
    }

    .value {
      color: #333;
      font-size: 14px;
    }
  }
}

.question-hint {
  margin: 16px;
  padding: 16px 20px;
  background-color: #ffffff;
  border-radius: 12px;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.08);

  .hint-text {
    font-size: 15px;
    color: #333;
    line-height: 1.4;
    font-weight: 500;
  }
}

.answer-content {
  margin: 16px;
  padding: 16px;
  background-color: rgba(64, 128, 255, 0.1);
  border-radius: 12px;
  font-size: 14px;
  color: #333;
  line-height: 1.5;
}

.control-buttons {
  display: flex;
  justify-content: center;
  gap: 24px;
  margin: 32px 0;

  .control-btn {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 24px;
    position: relative;

    &.pause {
      background-color: #ff6b6b;
    }

    &.record {
      background-color: #2d6cdf;
    }

    &.next {
      background-color: #40c057;
    }

    &.close {
      background-color: #f56c6c;
    }

    .record-tip {
      position: absolute;
      top: -30px;
      left: 50%;
      transform: translateX(-50%);
      font-size: 12px;
      color: #666;
      white-space: nowrap;
      background-color: rgba(0, 0, 0, 0.6);
      color: #fff;
      padding: 4px 8px;
      border-radius: 4px;
    }

    .btn-circle {
      width: 32px;
      height: 32px;
      border-radius: 50%;
      background-color: #fff;
      display: flex;
      align-items: center;
      justify-content: center;
    }
  }
}

.interview-tips {
  margin: 16px;
  padding: 16px;
  background-color: #fff9e6;
  border-radius: 12px;

  .tips-title {
    font-size: 15px;
    font-weight: 500;
    color: #333;
    margin-bottom: 8px;
  }

  .tips-content {
    font-size: 14px;
    color: #666;
    line-height: 1.5;
  }
}
</style>
